package com.vpa.graphics;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Paint;

import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;



public class GraphicsController 
{
	@SuppressLint("UseSparseArrays")
	protected ConcurrentHashMap<Integer, Spot> spots = new ConcurrentHashMap<Integer, Spot>();
	GLView gl;
	private int numspots = 0;
	Context c;
	static protected ConcurrentSkipListMap<String, TPC> fontCache = new ConcurrentSkipListMap<String, TPC>();
	
	public int addAnalogGauge(int min, int max, int gauge_resource, int needle_resource, String title, String units) throws ThreadedGraphicsException
	{
		threadCheck();
		
		ResourceBundle gauge = idToBundle(gauge_resource);
		ResourceBundle needle = idToBundle(needle_resource);
		if(gauge == null || needle == null)
			return -1;
		AnalogGauge s = new AnalogGauge(new Texture(gauge, gl), new Texture(needle, gl), min, max, title, units);
		spots.put(numspots, s);
		numspots ++;
		return numspots -1;
	}
	public int addImageSpot(int im_id) throws ThreadedGraphicsException
	{
		threadCheck();
		ResourceBundle b = idToBundle(im_id);
		ImageSpot s = new ImageSpot(new Texture(b, gl));
		spots.put(numspots, s);
		numspots ++;
		return numspots - 1;
	}
	public int addDigitalGauge(int gauge_resource, String title, String units) throws ThreadedGraphicsException
	{
		threadCheck();
		ResourceBundle gauge = idToBundle(gauge_resource);
		DigitalGauge s = new DigitalGauge(new Texture(gauge, gl), title, units);
		s.type = 1;
		spots.put(numspots, s);
		numspots ++;
		return numspots - 1;
	}
	
	public int addTextArea(int text_size) throws ThreadedGraphicsException
	{
		threadCheck();
		TextArea s = new TextArea();
		s.text_size = text_size;
		spots.put(numspots, s);
		numspots ++;
		s.type = 2;
		return numspots - 1;
	}
	
	public void removeSpot(int spot_num) throws ThreadedGraphicsException
	{
		threadCheck();
		spots.remove(Integer.valueOf(spot_num));
	}
	
	public boolean updateGauge(int spot_num, double value)
	{
		Spot s = spots.get(Integer.valueOf(spot_num));
		if(s == null)
			return false;
		switch(s.type)
		{
			case 0: ((AnalogGauge)s).setValue(value);
				break;
			case 1: ((DigitalGauge)s).setValue(value);
				break;
		}
		return true;
	}
	
	public boolean updateTextArea(int spot_num, int index, String value)
	{
		Spot s = spots.get(Integer.valueOf(spot_num));
		if(s == null)
			return false;
		((TextArea)s).setValue(index, value);
		return true;
	}
	
	public int addTextAreaElement(int spot_num, String title, String units)
	{
		Spot s = spots.get(Integer.valueOf(spot_num));
		if(s.type != 2)
			return -1;
		TextArea t = (TextArea)s;
		return t.addEntry(title, units);
	}
	
	public void removeTextAreaElement(int spot_num, int textAreaSpot)
	{
		Spot s = spots.get(Integer.valueOf(spot_num));
		if(s.type != 2)
			return;
		TextArea t = (TextArea)s;
		t.removeEntry(textAreaSpot);
	}
	
	public GraphicsController(GLView gl, Context c) throws ThreadedGraphicsException
	{
		this.c = c;
		this.gl = gl;
		gl.register(this);
	}
	
	public void threadCheck() throws ThreadedGraphicsException
	{
		if(Thread.currentThread() != gl.main)
			throw new ThreadedGraphicsException("You must call graphics functions on the thread that created GraphicsController");
	}
	
	public ResourceBundle idToBundle(int res_id)
	{
		Scanner reader = null;
		try 
		{
			InputStream is = c.getAssets().open("gfxtval.config");
			reader = new Scanner(is);
		}
		catch (IOException e) 
		{
			e.printStackTrace();
			System.exit(0);
		}
		ResourceBundle bun;
		if(reader != null)
		{	
			reader.findWithinHorizon(String.format("%x", res_id), 0);
			int w = reader.nextInt();
			int h = reader.nextInt();
			int	d = reader.nextInt();
			bun = new ResourceBundle(res_id, w, h, d);
			return bun;
		}
		else
			return null;
	}
	
	protected static String heiselify(String s, int digs)
	{
		if(s.length() >= digs)
		{
			return s.substring(0, digs);
		}
		else
		{
			String newstr = XSpaces((digs - s.length())/2) + s;
			newstr = newstr + XSpaces(digs - newstr.length());
			return newstr;
		}
	}
	
	protected static String doubleTrunc(double d, int dec)
	{
		return String.format("%."+ dec + "f", d);
	}
	
	private static String XSpaces(int num)
	{
		String ret = "";
		for(int i = 0; i < num; i++)
			ret += " ";
		return ret;
	}
}

class ResourceBundle
{
	int id;
	int width;
	int height;
	int fdim;
	Bitmap b = null;
	
	public ResourceBundle()
	{
	}
	
	public ResourceBundle(int i, int w, int h, int f)
	{
		id = i;
		width = w;
		height = h;
		fdim = f;
	}
	public ResourceBundle(Bitmap b, int w, int h, int f)
	{
		this.b = b; 
		width = w;
		height = h;
		fdim = f;
		id = -1;
	}
}

class TPC
{
	GLText text;
	Paint p;
	
	public TPC(GLText t, Paint pa)
	{
		text = t;
		p = pa;
	}
}
	